package spindles.gwt.client;

import spindles.gwt.shared.SettingsDTO;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.WindowResizeListener;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Spindles implements EntryPoint, WindowResizeListener {
	
	private static Spindles singleton;	

	/**
	 * Instantiate an application-level image bundle. This object will provide
	 * programmatic access to all the images needed by widgets.
	 */
	private static final Images images = (Images) GWT.create(Images.class);
	
	/**
	 * An aggregate image bundle that pulls together all the images for this
	 * application into a single bundle.
	 */
	public interface Images extends TopPanel.Images {}
	
	private TopPanel topPanel;	
	private TasksPanel tasks = new TasksPanel();	
	private RightPanel rightPanel;	
	
	private DockPanel outer = new DockPanel();
	
	private static final String WINDOW_FEATURES = "resizable=yes,scrollbars=yes";
	
	private Spindles(){}
	
	/**
	 * Gets the singleton Spindles instance.
	 */
	public static Spindles get() {
		return singleton;
	}

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		try {
			ErrorHandler.initErrorHandling();
			singleton = this;
			
			loadSettingsDTO();
			
			topPanel = new TopPanel(images);
			topPanel.setWidth("100%");	

			rightPanel = tasks.getSpindleDetectionPanel();

			addWidgets();    

			prepareWindow();

			// Finally, add the outer panel to the RootPanel, so that it will be
			// displayed.
			RootPanel.get().add(outer);

			refreshWindow();
		} catch (RuntimeException e) {
			ErrorHandler.showErrorDialog(e);
		}	
	}
	
	private void prepareWindow(){
		// Hook the window resize event, so that we can adjust the UI.
	    Window.addWindowResizeListener(this);

	    // Get rid of scrollbars, and clear out the window's built-in margin,
	    // because we want to take advantage of the entire client area.
	    Window.enableScrolling(false);
	    Window.setMargin("0px");
	}

	public void onWindowResized(int width, int height) {
		// Adjust the tasks panel and main area to take up the available room
		// in the window.
		int shortcutHeight = height - tasks.getAbsoluteTop() - 8;
		if (shortcutHeight < 1) {
			shortcutHeight = 1;
		}
		tasks.setHeight("" + shortcutHeight);

		// Give the right panel a chance to resize itself as well.
		rightPanel.setHeight(shortcutHeight);
	}
	
	private void removeWidgets(){
		outer.remove(topPanel);
	    outer.remove(tasks);
	    outer.remove(rightPanel);
	}
	
	private void addWidgets(){
		
		// Create a dock panel that will contain the menu bar at the top,
	    // the tasks to the left, and the master & details taking the rest.	    
	    outer.add(topPanel, DockPanel.NORTH);
	    outer.add(tasks, DockPanel.WEST);
	    outer.add(rightPanel, DockPanel.CENTER);
	    outer.setWidth("100%");

	    outer.setSpacing(4);
	    outer.setCellWidth(rightPanel, "100%");    

	    refreshWindow();
	}
	
	private void refreshWindow(){
		// Call the window resized handler to get the initial sizes setup. Doing
	    // this in a deferred command causes it to occur after all widgets' sizes
	    // have been computed by the browser.
	    DeferredCommand.addCommand(new Command() {
	      public void execute() {
	        onWindowResized(Window.getClientWidth(), Window.getClientHeight());
	      }
	    });

	    onWindowResized(Window.getClientWidth(), Window.getClientHeight());	
	}
	
	public void setRightPanel(RightPanel newRightPanel){		
		removeWidgets();
		
		this.rightPanel = newRightPanel;
		
		addWidgets();
	}
	
	public static void showInfoDialog(String title, String body){
		InfoDialog dlg = new InfoDialog(title, body);
		dlg.show();
		dlg.center();
	}
	
	public static AsyncCallback createCallBack(final Callback command){
		AsyncCallback callback = new AsyncCallback() {
			public void onSuccess(Object result) {				
				command.execute(result);
			}
	
			public void onFailure(Throwable caught) {
				ErrorHandler.showErrorDialog(caught);
			}
		};
		
		return callback;	
	}
	
	private void loadSettingsDTO(){
		Callback cmd = new Callback(){

			public void execute(Object result) {
				Registry.setSettings((SettingsDTO)result);				
			}
			
		};
		
		ServerGateway.getSettings(Spindles.createCallBack(cmd));
	}
	
	public static void openWindow(String url){
		Window.open(url, "", WINDOW_FEATURES);
	}
}
